package vip.xiaonuo.bi.modular.dataset.service.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import vip.xiaonuo.bi.core.datasource.util.DButils;
import vip.xiaonuo.bi.core.datasource.util.DatasizeUtils;
import vip.xiaonuo.bi.core.datasource.util.DorisUtils;
import vip.xiaonuo.bi.core.datasource.util.ExcelExportUtils;
import vip.xiaonuo.bi.modular.dataset.dispatcher.InvokeDataSetProcess;
import vip.xiaonuo.bi.modular.dataset.dto.PreviewDto;
import vip.xiaonuo.bi.modular.dataset.entity.DataColumns;
import vip.xiaonuo.bi.modular.dataset.entity.Dataset;
import vip.xiaonuo.bi.modular.dataset.enums.DatasetType;
import vip.xiaonuo.bi.modular.dataset.mapper.DatasetMapper;
import vip.xiaonuo.bi.modular.dataset.param.DataSetAddParam;
import vip.xiaonuo.bi.modular.dataset.param.DataSetPageParam;
import vip.xiaonuo.bi.modular.dataset.param.DataSetTypeParam;
import vip.xiaonuo.bi.modular.dataset.param.DatasetInfo;
import vip.xiaonuo.bi.modular.dataset.service.DatasetService;
import vip.xiaonuo.bi.modular.datasource.doris.DorisTbService;
import vip.xiaonuo.bi.modular.datasource.dto.Colunm;
import vip.xiaonuo.bi.modular.datasource.service.DataColumnsService;
import vip.xiaonuo.bi.modular.datasource.service.DatasourceInfoService;
import vip.xiaonuo.common.cache.CommonCacheOperator;
import vip.xiaonuo.common.enums.CommonSortOrderEnum;
import vip.xiaonuo.common.exception.CommonException;
import vip.xiaonuo.common.page.CommonPageRequest;

import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static vip.xiaonuo.bi.core.datasource.util.CSVutils.uploadCsv;
import static vip.xiaonuo.bi.core.datasource.util.DateTypePredictUtils.getETLType;
import static vip.xiaonuo.bi.core.datasource.util.ExcelImportUtils.uploudExcel;

/**
 * 数据集表Service接口实现类
 *        System.out.println(StpLoginUserUtil.getLoginUser().getId()); // 根据token获取用户信息
 * @author 顾育司
 * @date  2023/12/15 12:09
 **/
@Service
@Transactional(rollbackFor = Exception.class)
public class DatasetServiceImpl extends ServiceImpl<DatasetMapper, Dataset> implements DatasetService {

    @Autowired
    DorisTbService dorisTbService;

    @Autowired
    CommonCacheOperator redisCacheOperator;

    @Autowired
    DatasetService datasetService;

    @Autowired
    InvokeDataSetProcess invokeDataSetProcess;

    @Autowired
    DataColumnsService dataColumnsService;

    @Autowired
    DatasourceInfoService datasourceInfoService;

//    @Autowired
//    InvokeDataSetProcess invokeDataSetProcess;
    @Override
    public Page<Dataset> page(DataSetPageParam dataSetPageParam) {
        //创建查询条件
        QueryWrapper<Dataset> queryWrapper = new QueryWrapper<>();
        //如果传入的排序字段和排序方式都不为空，则添加排序条件
        if(ObjectUtil.isAllNotEmpty(dataSetPageParam.getSortField(), dataSetPageParam.getSortOrder())) {
            CommonSortOrderEnum.validate(dataSetPageParam.getSortOrder());
            queryWrapper.orderBy(true, dataSetPageParam.getSortOrder().equals(CommonSortOrderEnum.ASC.getValue()),
                    StrUtil.toUnderlineCase(dataSetPageParam.getSortField()));
        } else {
            //否则，按照ID升序排列
            queryWrapper.lambda().orderByAsc(Dataset::getId);
        }


        //返回分页查询结果
        return this.page(CommonPageRequest.defaultPage(), queryWrapper);
    }




    @Override
    public PreviewDto upload(MultipartFile file, String type, String charset, String colInfoJson) {
        if(DatasetType.FILE_CSV.name().equals(type.toUpperCase())){
          return   uploadCsv(file,charset,colInfoJson);
        }
        return uploudExcel(file,colInfoJson);
    }


    @Override
    @Transactional
    public void addDataset(DataSetAddParam dataSetAddParam,MultipartFile file) {

        /************ 保存数据集信息   ********/
        //1 根据类型type解析参数
        DataSetTypeParam dataSetTypeParam = DatasetType.parseParam(dataSetAddParam.getType(), dataSetAddParam.getDataJson());
        Dataset dataset = new Dataset();

        // 获取表名==》 设置名称 描述 类型 数据配置信息
        BeanUtils.copyProperties(dataSetAddParam,dataset);
        String dorisTable = invokeDataSetProcess.getTarget(dataSetAddParam.getType()).getDorisTable();
        dataSetTypeParam.setTable(dorisTable);

        // 根据表 +列信息==》 创建doris表
        List<Colunm> colunms = dataSetTypeParam.getColunms();
        String careteTableSql = DorisUtils.createTableSql(colunms.stream().collect(Collectors.toMap(Colunm::getName,Colunm::getType)), dorisTable, "id");
        dorisTbService.exeDDLsql(careteTableSql);

        // 数据存入 ==》 doris表
        dataSetTypeParam.setFile(file);
        dorisTbService.exeInsertData(invokeDataSetProcess.getTarget(dataSetAddParam.getType()).getData(dataSetTypeParam), colunms.stream().collect(Collectors.toMap(Colunm::getName,Colunm::getType)), dorisTable, colunms.stream().map(item->item.getName()).collect(Collectors.toList()));

        // 设置数据统计信息：行总数 列总数 数据量大小
        DatasetInfo datasetInfo = invokeDataSetProcess.getTarget(dataSetAddParam.getType()).getCount(dataSetTypeParam);
        BeanUtils.copyProperties(datasetInfo,dataset);
        dataset.setDataSize(DatasizeUtils.calculateSize(datasetInfo.getDataSize())); // 换算成数据大小

        // 保存配置
        dataSetTypeParam.setFile(null);
        dataset.setDataJson(JSONObject.toJSON(dataSetTypeParam).toString());
        datasetService.save(dataset);


        /************ 保存字段    ********/
        List<DataColumns> columns = new ArrayList<>();
        colunms.stream().forEach(item->{
            DataColumns dataColumns = new DataColumns();
            dataColumns.setDatasetId(dataset.getId());
            dataColumns.setName(item.getName());
            dataColumns.setAlias(item.getAlias());
            dataColumns.setType(item.getType());
            dataColumns.setTableCol(item.getName());
            dataColumns.setClassify(getETLType(item.getType()));
            columns.add(dataColumns);
        });
        dataColumnsService.saveBatch(columns);
    }


    @Override
    public Object getPreView(Long id, Integer limit) {
        Dataset byId = this.getById(id);

        // 解析配置
        DataSetTypeParam dataSetTypeParam = JSONObject.parseObject(byId.getDataJson(), DataSetTypeParam.class);
        String table = dataSetTypeParam.getTable();
        List<DataColumns> list = dataColumnsService.list(new LambdaQueryWrapper<DataColumns>().eq(DataColumns::getDatasetId, id));
        String tablePreViewSql = DButils.getTablePreViewSqlByCols(list,table, limit);

        // 执行获取数据
        List<List<String>> data = dorisTbService.exeQuerySql1(tablePreViewSql);
        List<String> columns = data.get(0);
        List<List<String>> result = data.subList(1, data.size());

        // 执行获取字段数据
        List<DataColumns> Columns = dataColumnsService.list(new LambdaQueryWrapper<DataColumns>().eq(DataColumns::getDatasetId, id));
        Map<String, DataColumns> cols = Columns.stream().collect(Collectors.toMap(DataColumns::getTableCol, item -> item));

        // 返回数据集
        PreviewDto previewDto = new PreviewDto();
        previewDto.setColums(columns.stream().map(item->new Colunm(item,cols.get(item).getAlias(),cols.get(item).getType())).collect(Collectors.toList()));
        previewDto.setData(result);
        return previewDto;
    }

    @Override
    public List<DataColumns> getColInfo(Long id) {
        List<DataColumns> list = dataColumnsService.list(new LambdaQueryWrapper<DataColumns>().eq(DataColumns::getDatasetId, id));
        return list;
    }

    @Override
    public void exportFile(HttpServletResponse response, Long id) throws Exception {
        try {
            Dataset byId = this.getById(id);

            // 创建临时文件
            // 解析配置
            DataSetTypeParam dataSetTypeParam = JSONObject.parseObject(byId.getDataJson(), DataSetTypeParam.class);
            String table = dataSetTypeParam.getTable();

            List<DataColumns> list = dataColumnsService.list(new LambdaQueryWrapper<DataColumns>().eq(DataColumns::getDatasetId, id));
            String tablePreViewSql = DButils.getTablePreViewSqlByCols(list, table, null);

            // 执行获取数据
            List<List<String>> data = dorisTbService.exeQuerySql1(tablePreViewSql);
            if (data.size() < 1) {
                throw new CommonException("该数据集没有数据导出");
            }
            List<String> columns = data.get(0);
            List<List<String>> result = data.subList(1, data.size());

            // 导出excel
           // 设置响应头
           ExcelExportUtils.setExcelHeader(response, byId.getName());
            //  导出文件
           ExcelExportUtils.exportToExcel(response, result,  byId.getName(),  byId.getName(), columns);

        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    @Override
    public void removeByDataSetId(String id) {
        // 删除数据集
        this.removeById(id);
        // 删除数据集相关字段
        dataColumnsService.remove(new LambdaQueryWrapper<DataColumns>().eq(DataColumns::getDatasetId,id));
    }
}